 #ifndef audio_h
#define audio_h

#include <cmath>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <map>

#include "AudioDevice.h"
#include "Debugging.h"
#include "IIRFilter.h"
#include "IODataTypes.h"
#include "TubeScreamer.h"
#include "RtAudio.h"

#include <Core>
#include <Dense>
#include <Eigenvalues>

typedef signed short MY_TYPE;

//define FORMAT RTAUDIO_SINT16
#define SCALE  32767.0

// Sleep command specific to Windows
#define SLEEP( milliseconds ) Sleep( (DWORD) milliseconds ) 

//	Namespace for Linear Algebra functions from the Eigen Library
using namespace Eigen;

//	Standard namespace
using namespace std;

/** Constant to specify format for Real Time Audio data */
#define FORMAT RTAUDIO_FLOAT64

/** Enumerated type that specifies the device to read the input stream from */
enum inputDevice { MICROPHONE = 0, LINEIN = 1 };

/** Enumerated type that specifies the device to write the output stream to */
enum outputDevice { SPEAKERS = 2 };


/* * * * * * * * * * * * * * * * * CONSTANTS * * * * * * * * * * * * * * * * */

/** The number of audio channels (1 for mono, 2 for stereo) */
#define NUM_CHANNELS 1

/** Sampling frequency (in Hertz) of the input and output channels */
#define SAMPLING_FREQUENCY 96000

/** 
* The device to be used for audio input (in the future this might not be a 
* constant
*/
#define DEFAULT_INPUT_DEVICE 0

/** 
* The device to be used for audio output (there is only one option 
* currently) 
*/
#define DEFAULT_OUTPUT_DEVICE 2

/** Number of samples per channel per buffer */
#define NUM_BUFFER_FRAMES 512


int ioOps(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, 
		  double streamTime, RtAudioStreamStatus status, void *data);
vector<audioDevice> audioProbe(RtAudio & audio);



/* * * * * * * * * * * * * * * FUNCTION DEFINITIONS * * * * * * * * * * * * * */

/**
* Primary function responsible for generating an output buffer from an input
* buffer. Interfaces with the RTAudio class and provides a framework to process
* input/output signals. By default, just copies the input buffer directly to
* the output buffer.
*
* @param outputBuffer The buffer of data to be written to the output of the 
* program (currently the speakers of the computer)
*
* @param inputBuffer The buffer of data read from the input to the program
* (either the line-in port or the built-in microphone)
*
* @param nBufferFrames The number of frames (data samples) in inputBuffer and 
* outputBuffer
*
* @param streamTime The time since the stream was opened at the first frame of
* the buffer
*
* @param status A variable containing information about the status of the
* stream. If stream is false, then everything is normal
*
* @param data A variable containing a pointer to any other data needed for this
* function (including a pointer to any callback functions needed for audio 
* processing and any data required by these functions)
*
* @return An integer encoding information about the successful execution of 
* this function. A zero indicates successful execution with no problems.
*/
int fileRead(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, 
		  double streamTime, RtAudioStreamStatus status, void *data);
/**
 * Primary function responsible for generating an output buffer from an input
 * buffer. Interfaces with the RTAudio class and provides a framework to process
 * input/output signals. By default, just copies the input buffer directly to
 * the output buffer.
 *
 * @param outputBuffer The buffer of data to be written to the output of the 
 * program (currently the speakers of the computer)
 *
 * @param inputBuffer The buffer of data read from the input to the program
 * (either the line-in port or the built-in microphone)
 *
 * @param nBufferFrames The number of frames (data samples) in inputBuffer and 
 * outputBuffer
 *
 * @param streamTime The time since the stream was opened at the first frame of
 * the buffer
 *
 * @param status A variable containing information about the status of the
 * stream. If stream is false, then everything is normal
 *
 * @param data A variable containing a pointer to any other data needed for this
 * function (including a pointer to any callback functions needed for audio 
 * processing and any data required by these functions)
 *
 * @return An integer encoding information about the successful execution of 
 * this function. A zero indicates successful execution with no problems.
 */
int ioOps(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, 
					double streamTime, RtAudioStreamStatus status, void *data);
vector<audioDevice> *audioProbe(RtAudio & audio, int & defaultInput, int & defaultOutput);
int printMainMenu();
void printDistortionParameters(int gain, int tone, int volume, int dirty);
void setDistortionParameters(int & gain, int & tone, int & volume, int & dirty);
void listAudioDevices(vector<audioDevice> & devices, unsigned int iDevice, unsigned int oDevice);
void playWaveFile(RtAudio & adac, unsigned int iDevice, unsigned int oDevice,
				 int gain, int tone, int volume, int dirty, vector<audioDevice> & devices);
void playLiveStream(RtAudio & adac, unsigned int iDevice, unsigned int oDevice,
					int gain, int tone, int volume, int dirty, vector<audioDevice> & devices);
vector<audioDevice> *getDevices();
void setDevices(vector<audioDevice> *newDevices);
RtAudio *getADAC();

#endif